import { initShaders } from '@/lib/webgl'

export default class {
    constructor (el, datas, indices, normals, color, matrix, lightColor, lightPosition, ambientLight, normalMatrix, modelMatrix, fshader = false, drawType = 0) {
        const styles = window.getComputedStyle(el, null)
        el.width = parseInt(styles.width)
        el.height = parseInt(styles.height)
        const gl = el.getContext('webgl2')
        gl.enable(gl.DEPTH_TEST)

        if (!fshader) {
            // 顶点着色器
            const VSHADER_SOURCE = `
                attribute vec4 a_Position;
                attribute vec4 a_Color;
                attribute vec4 a_Normal;
                uniform mat4 u_Matrix;
                uniform mat4 u_ModelMatrix;
                uniform mat4 u_NormalMatrix;
                uniform vec3 u_LightColor;
                uniform vec3 u_LightPosition;
                uniform vec3 u_AmbientLight;
                varying vec4 v_Color;
                void main() {
                    gl_Position = u_Matrix * a_Position;
                    vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));
                    vec4 vertexPosition = u_ModelMatrix * a_Position;
                    vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));
                    float nDotL = max(dot(lightDirection, normal), 0.0);
                    vec3 diffuse = u_LightColor * vec3(a_Color) * nDotL;
                    vec3 ambient = u_AmbientLight * a_Color.rgb;
                    v_Color = vec4(diffuse + ambient, a_Color.a);
                }
            `
            const FSHADER_SOURCE = `
                precision mediump float;
                varying vec4 v_Color;
                void main() {
                    gl_FragColor = v_Color;
                }
            `
            if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
                console.log('init shader error')
                return
            }
        } else { // 逐片元渲染模式
            // 顶点着色器
            const VSHADER_SOURCE = `
                attribute vec4 a_Position;
                attribute vec4 a_Color;
                attribute vec4 a_Normal;
                uniform mat4 u_Matrix;
                uniform mat4 u_ModelMatrix;
                uniform mat4 u_NormalMatrix;
                varying vec4 v_Color;
                varying vec3 v_Normal;
                varying vec3 v_Position;
                void main() {
                    gl_Position = u_Matrix * a_Position;
                    v_Position = vec3(u_ModelMatrix * a_Position);
                    v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));
                    v_Color = a_Color;
                }
            `
            const FSHADER_SOURCE = `
                precision mediump float;
                uniform vec3 u_LightColor;
                uniform vec3 u_LightPosition;
                uniform vec3 u_AmbientLight;
                varying vec3 v_Normal;
                varying vec3 v_Position;
                varying vec4 v_Color;
                void main() {
                    vec3 normal = normalize(v_Normal);
                    vec3 lightDirection = normalize(u_LightPosition - v_Position);
                    float nDotL = max(dot(lightDirection, normal),0.0);
                    vec3 diffuse = u_LightColor * v_Color.rgb * nDotL;
                    vec3 ambient = u_AmbientLight * v_Color.rgb;
                    gl_FragColor = vec4(diffuse + ambient, v_Color.a);
                }
            `
            if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
                console.log('init shader error')
                return
            }
        }
        const initVertexBuffers = (gl) => {
            // 创建缓冲区
            const verticeBuffer = gl.createBuffer()
            const indexBuffer = gl.createBuffer()
            const normalBuffer = gl.createBuffer()
            if (!verticeBuffer || !indexBuffer || !normalBuffer) {
                return -1
            }

            gl.bindBuffer(gl.ARRAY_BUFFER, verticeBuffer)
            gl.bufferData(gl.ARRAY_BUFFER, datas, gl.STATIC_DRAW)
            const aPosition = gl.getAttribLocation(gl.program, 'a_Position')
            gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 0, 0)
            gl.enableVertexAttribArray(aPosition)

            gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer)
            gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW)
            const aNormal = gl.getAttribLocation(gl.program, 'a_Normal')
            gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, false, 0, 0)
            gl.enableVertexAttribArray(aNormal)

            const aColor = gl.getAttribLocation(gl.program, 'a_Color')
            gl.vertexAttrib3f(aColor, ...color)

            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW)
            return indices.length
        }

        // 设置顶点位置
        const n = initVertexBuffers(gl)
        if (n < 0) {
            console.log('initVertexBuffers failed')
            return
        }

        // 设置视图/变换矩阵
        const uMatrix = gl.getUniformLocation(gl.program, 'u_Matrix')
        gl.uniformMatrix4fv(uMatrix, false, matrix)

        // 设置光照颜色
        const uLightColor = gl.getUniformLocation(gl.program, 'u_LightColor') // [1.0, 1.0, 1.0]
        gl.uniform3f(uLightColor, ...lightColor)

        // 设置点光源位置
        const uLightPosition = gl.getUniformLocation(gl.program, 'u_LightPosition') // [1.0, 1.0, 1.0]
        gl.uniform3f(uLightPosition, ...lightPosition)

        // 设置环境光颜色
        const uAmbientLightColor = gl.getUniformLocation(gl.program, 'u_AmbientLight') // [1.0, 1.0, 1.0]
        gl.uniform3f(uAmbientLightColor, ...ambientLight)

        // 设置变换的逆转置矩阵
        const uNormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix')
        gl.uniformMatrix4fv(uNormalMatrix, false, normalMatrix)

        // 设置模型矩阵
        const uModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix')
        gl.uniformMatrix4fv(uModelMatrix, false, modelMatrix)

        gl.clearColor(0.0, 0.0, 0.0, 1.0)
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
        gl.drawElements(gl.TRIANGLES, n, drawType == 0 ? gl.UNSIGNED_BYTE : gl.UNSIGNED_SHORT, 0)

        this.gl = gl
        this.el = el
        this.vertexCount = n
        this.img = el.toDataURL('image/png')
    }

    redraw (matrix, normalMatrix, modelMatrix, drawType = 0) {
        const gl = this.gl
        const el = this.el

        const uMatrix = gl.getUniformLocation(gl.program, 'u_Matrix')
        gl.uniformMatrix4fv(uMatrix, false, matrix)

        const uNormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix')
        gl.uniformMatrix4fv(uNormalMatrix, false, normalMatrix)

        const uModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix')
        gl.uniformMatrix4fv(uModelMatrix, false, modelMatrix)

        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
        gl.drawElements(gl.TRIANGLES, this.vertexCount, drawType == 0 ? gl.UNSIGNED_BYTE : gl.UNSIGNED_SHORT, 0)
        this.img = el.toDataURL('image/png')
    }
}